//  Epsilon.java
//
//  Author:
//       Antonio J. Nebro <antonio@lcc.uma.es>
//       Juan J. Durillo <durillo@lcc.uma.es>
//
//  Copyright (c) 2011 Antonio J. Nebro, Juan J. Durillo
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
// 
//  You should have received a copy of the GNU Lesser General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.

package etmo.qualityIndicator;

/**
 * This class implements the unary epsilon additive indicator as proposed in E.
 * Zitzler, E. Thiele, L. Laummanns, M., Fonseca, C., and Grunert da Fonseca. V
 * (2003): Performance Assesment of Multiobjective Optimizers: An Analysis and
 * Review. The code is the a Java version of the original metric implementation
 * by Eckart Zitzler. It can be used also as a command line program just by
 * typing $java jmetal.qualityIndicator.Epsilon
 * <solutionFrontFile> <trueFrontFile> <getNumberOfObjectives>
 */

public class Epsilon {

	/* stores the number of objectives */
	int dim_;
	/*
	 * obj_[i]=0 means objective i is to be minimized. This code always assume
	 * the minimization of all the objectives
	 */
	int[] obj_; /* obj_[i] = 0 means objective i is to be minimized */
	/*
	 * method_ = 0 means apply additive epsilon and method_ = 1 means
	 * multiplicative epsilon. This code always apply additive epsilon
	 */
	int method_;
	/* stores a reference to qualityIndicatorUtils */
	public etmo.qualityIndicator.util.MetricsUtil utils_ = new etmo.qualityIndicator.util.MetricsUtil();

	/**
	 * Returns the epsilon indicator.
	 * 
	 * @param b
	 *            True Pareto front
	 * @param a
	 *            Solution front
	 * @return the value of the epsilon indicator
	 */
	public double epsilon(double[][] b, double[][] a, int dim) {
		int i, j, k;
		double eps, eps_j = 0.0, eps_k = 0.0, eps_temp;

		dim_ = dim;
		set_params();

		if (method_ == 0)
			eps = Double.MIN_VALUE;
		else
			eps = 0;

		for (i = 0; i < a.length; i++) {
			for (j = 0; j < b.length; j++) {
				for (k = 0; k < dim_; k++) {
					switch (method_) {
					case 0:
						if (obj_[k] == 0)
							eps_temp = b[j][k] - a[i][k];
						// eps_temp = b[j * dim_ + k] - a[i * dim_ + k];
						else
							eps_temp = a[i][k] - b[j][k];
						// eps_temp = a[i * dim_ + k] - b[j * dim_ + k];
						break;
					default:
						if ((a[i][k] < 0 && b[j][k] > 0) || (a[i][k] > 0 && b[j][k] < 0)
								|| (a[i][k] == 0 || b[j][k] == 0)) {
							// if ( (a[i * dim_ + k] < 0 && b[j * dim_ + k] > 0)
							// ||
							// (a[i * dim_ + k] > 0 && b[j * dim_ + k] < 0) ||
							// (a[i * dim_ + k] == 0 || b[j * dim_ + k] == 0)) {
							System.err.println("error in data file");
							System.exit(0);
						}
						if (obj_[k] == 0)
							eps_temp = b[j][k] / a[i][k];
						// eps_temp = b[j * dim_ + k] / a[i * dim_ + k];
						else
							eps_temp = a[i][k] / b[j][k];
						// eps_temp = a[i * dim_ + k] / b[j * dim_ + k];
						break;
					}
					if (k == 0)
						eps_k = eps_temp;
					else if (eps_k < eps_temp)
						eps_k = eps_temp;
				}
				if (j == 0)
					eps_j = eps_k;
				else if (eps_j > eps_k)
					eps_j = eps_k;
			}
			if (i == 0)
				eps = eps_j;
			else if (eps < eps_j)
				eps = eps_j;
		}
		return eps;
	} // epsilon

	/**
	 * Established the params by default
	 */
	void set_params() {
		int i;
		obj_ = new int[dim_];
		for (i = 0; i < dim_; i++) {
			obj_[i] = 0;
		}
		method_ = 0;
	} // set_params

	/**
	 * Returns the additive-epsilon value of the paretoFront. This method call
	 * to the calculate epsilon-indicator one
	 */
	public static void main(String[] args) {
		double ind_value;

		if (args.length < 2) {
			System.err.println("Error using Epsilon. Type: \n java AdditiveEpsilon " + "<FrontFile>"
					+ "<TrueFrontFile> + <getNumberOfObjectives>");
			System.exit(1);
		}

		Epsilon qualityIndicator = new Epsilon();
		double[][] solutionFront = qualityIndicator.utils_.readFront(args[0]);
		double[][] trueFront = qualityIndicator.utils_.readFront(args[1]);
		// qualityIndicator.dim_ = trueParetoFront[0].length;
		// qualityIndicator.set_params();

		ind_value = qualityIndicator.epsilon(trueFront, solutionFront, new Integer(args[2]));

		System.out.println(ind_value);
	} // main
} // Epsilon
